package com.udata.server.util;

import java.util.Iterator;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

public class JsonFormatter {

	public String format(final JSONObject object) throws JSONException {
		final JsonVisitor visitor = new JsonVisitor(4, ' ');
		visitor.visit(object, 0, false);
		return visitor.toString();
	}

	private static class JsonVisitor {

		private final StringBuilder builder = new StringBuilder();
		private final int indentationSize;
		private final char indentationChar;

		public JsonVisitor(final int indentationSize, final char indentationChar) {
			this.indentationSize = indentationSize;
			this.indentationChar = indentationChar;
		}

		private void visit(final JSONArray array, final int indent,
				boolean needComma) throws JSONException {
			final int length = array.length();
			if (length == 0) {
				write("[]", indent, true);
			} else {
				write("[", indent, true);
				for (int i = 0; i < length; i++) {
					if (i != length - 1) {
						visit(array.get(i), indent + 1, true);
					} else {
						visit(array.get(i), indent + 1, false);
					}
				}
				if (needComma) {
					write("],", indent, true);
				} else {
					write("]", indent, true);
				}
			}

		}

		private void visit(final JSONObject obj, final int indent,
				boolean needComma) throws JSONException {
			final int length = obj.length();
			if (length == 0) {
				write("{}", indent, true);
			} else {
				write("{", indent, true);
				final Iterator<String> keys = obj.keys();
				while (keys.hasNext()) {
					final String key = keys.next();
					if (obj.get(key) instanceof JSONObject
							|| obj.get(key) instanceof JSONArray) {
						write("\"" + key + "\":", indent + 1, false);
						boolean needCommaTmp = false;
						if (keys.hasNext()) {
							needCommaTmp = true;
						}
						visit(obj.get(key), indent + 1, needCommaTmp);

					} else {
						String valueTmp = obj.get(key).toString().toLowerCase();
						String tmp = null;
						if (valueTmp.equals("true") || valueTmp.equals("false")
								|| valueTmp.equals("null")) {
							tmp = "\"" + key + "\": " + obj.get(key);
						} else {
							tmp = "\"" + key + "\": \"" + obj.get(key) + "\"";
						}

						if (keys.hasNext()) {
							tmp += ",";
						}
						write(tmp, indent + 1, true);

					}
				}
				if (needComma) {
					write("},", indent, true);
				} else {
					write("}", indent, true);
				}
			}

		}

		private void visit(final Object object, final int indent,
				boolean needComma) throws JSONException {
			if (object instanceof JSONArray) {
				visit((JSONArray) object, indent, needComma);
			} else if (object instanceof JSONObject) {
				visit((JSONObject) object, indent, needComma);
			} else {
				if (object instanceof String) {
					write("\"" + (String) object + "\"", indent, true);
				} else {
					write(String.valueOf(object), indent, true);
				}
			}

		}

		private void write(final String data, final int indent,
				boolean needChangeline) {
			for (int i = 0; i < (indent * indentationSize); i++) {
				builder.append(indentationChar);
			}
			builder.append(data);
			builder.append('\n');

		}

		@Override
		public String toString() {
			return builder.toString();
		}

	}

}
